`include "defines.svh"
`include "CP0Defines.svh"
module ForwardUnit (
    input logic MEM_CP0Wr,
    input logic [4:0]ID_Rs,
    input logic [4:0]ID_Rt,

    input logic [31:0]ID_Rs_Data,
    input logic [31:0]ID_Rt_Data,

    input logic [31:0]ALU_Out_End,
    input logic [31:0]Data_From_DM_AfterExt,
    input logic [31:0]MEM_ALU_Out,
    input logic [31:0]MEM2_ALU_Out,

    input logic [4:0]EXE_RW,
    input logic [4:0]MEM_RW,
    input logic [4:0]MEM2_RW,
    input logic EXE_MemToRegWr,
    input logic MEM_MemToRegWr,
    input logic MEM2_MemToRegWr,
    input logic [31:0]MEM2_CP0RdData,

    input logic [31:0]EXE_Instr,
    input logic [31:0]EXE_PC,
    input logic [31:0]MEM_Instr,
    input logic [31:0]MEM_PC,
    input logic [31:0]MEM2_Instr,
    input logic [31:0]MEM2_PC,

    input logic [4:0]EXE_Rs,
    input logic [4:0]EXE_Rt,
    input logic [4:0]WB_RW,
    input logic [31:0]WB_CP0RdData,
    input logic [1:0]WB_Data_To_Reg_Sel,
    input logic [1:0]MEM2_Data_To_Reg_Sel,
    input logic [31:0]EXE_Rs_Data,
    input logic [31:0]EXE_Rt_Data,
    output logic[31:0]EXE_Rs_Data_End,
    output logic [31:0]EXE_Rt_Data_End,

    output logic [31:0]ID_Rs_Data_End,
    output logic [31:0]ID_Rt_Data_End
);
    always_comb begin
        if((ID_Rs == EXE_RW) && (!EXE_MemToRegWr) && (EXE_RW != '0))              //EXE->ID
                ID_Rs_Data_End = ALU_Out_End;
        else if((ID_Rs == MEM_RW) && (!MEM_MemToRegWr) && (MEM_RW != '0))         //MEM->ID(不读存储器)
            if((MEM_Instr[31:26] == `jal)||MEM_Instr[31:26]==`b_special&&(MEM_Instr[20:16]==`bgezal||MEM_Instr[20:16]==`bltzal))        //写入寄存器的值可能是PC+8,可能ID级要取31号寄存器
                ID_Rs_Data_End=MEM_PC+8;
            else
                ID_Rs_Data_End = MEM_ALU_Out;  
        else if((ID_Rs == MEM2_RW) && (!MEM2_MemToRegWr) && (MEM2_RW != '0))       //MEM2的时候目标寄存器是MEM2_RW,指令时R型的，
            if((MEM2_Instr[31:26] == `jal)||MEM2_Instr[31:26]==`b_special&&(MEM2_Instr[20:16]==`bgezal||MEM2_Instr[20:16]==`bltzal))        //写入寄存器的值可能是PC+8,可能ID级要取31号寄存器
                ID_Rs_Data_End=MEM2_PC+8;
            else
                ID_Rs_Data_End = MEM2_ALU_Out;          
        else if((ID_Rs == MEM2_RW) && (MEM2_MemToRegWr) && (MEM2_RW != '0))          //MEM->ID(读存储器)
            ID_Rs_Data_End = Data_From_DM_AfterExt;
        else 
            ID_Rs_Data_End = ID_Rs_Data;
    end

    always_comb begin
        if((ID_Rt == EXE_RW) && (!EXE_MemToRegWr) && (EXE_RW != '0))              //EXE->ID
                ID_Rt_Data_End = ALU_Out_End;
        else if((ID_Rt == MEM_RW) && (!MEM_MemToRegWr) && (MEM_RW != '0))         //MEM->ID(不读存储器)
            if((MEM_Instr[31:26] == `jal)||MEM_Instr[31:26]==`b_special&&(MEM_Instr[20:16]==`bgezal||MEM_Instr[20:16]==`bltzal))        //写入寄存器的值可能是PC+8,可能ID级要取31号寄存器
                ID_Rt_Data_End=MEM_PC+8;
            else
                ID_Rt_Data_End = MEM_ALU_Out;  
        else if((ID_Rt == MEM2_RW) && (!MEM2_MemToRegWr) && (MEM2_RW != '0))       //MEM2的时候目标寄存器是MEM2_RW,指令时R型的，
            if((MEM2_Instr[31:26] == `jal)||MEM2_Instr[31:26]==`b_special&&(MEM2_Instr[20:16]==`bgezal||MEM2_Instr[20:16]==`bltzal))        //写入寄存器的值可能是PC+8,可能ID级要取31号寄存器
                ID_Rt_Data_End=MEM2_PC+8;
            else
                ID_Rt_Data_End = MEM2_ALU_Out;  
        else if((ID_Rt == MEM2_RW) && (MEM2_MemToRegWr) && (MEM2_RW != '0))       //MEM2是load指令时，发生了数据冒险
            ID_Rt_Data_End = Data_From_DM_AfterExt;
        else 
            ID_Rt_Data_End = ID_Rt_Data;
    end

    // 可能mfc0后面加b型或R型指令，用的数据与mfc0写入的冲突;
    // mfc0后面紧跟b或R型指令造成冲突的时候,先阻塞然后再旁路
    always_comb begin
        if((EXE_Rs==WB_RW)&&(WB_Data_To_Reg_Sel==2'b11))
            EXE_Rs_Data_End=WB_CP0RdData;
        else if((EXE_Rs==MEM2_RW)&&(MEM2_Data_To_Reg_Sel==2'b11))
            EXE_Rs_Data_End=MEM2_CP0RdData;
        else 
            EXE_Rs_Data_End=EXE_Rs_Data;
    end

    always_comb begin
        if((EXE_Rt==WB_RW)&&(WB_Data_To_Reg_Sel==2'b11))
            EXE_Rt_Data_End=WB_CP0RdData;
        else if((EXE_Rt==MEM2_RW)&&(MEM2_Data_To_Reg_Sel==2'b11))
            EXE_Rt_Data_End=MEM2_CP0RdData;
        else 
            EXE_Rt_Data_End=EXE_Rt_Data;
    end

endmodule

    